package me.itsoo.artemis.framework.core.util;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Objects;

/**
 * ArrayUtils
 *
 * @author zxy
 * @version 0.0.1
 * @since 2023/5/11
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class ArrayUtils {

    /**
     * 数组为空
     *
     * @param array Object[]
     * @return boolean
     */
    public static boolean isEmpty(Object[] array) {
        return (array == null) || (array.length == 0);
    }

    /**
     * 数组不为空
     *
     * @param array Object[]
     * @return boolean
     */
    public static boolean isNotEmpty(Object[] array) {
        return !isEmpty(array);
    }

    /**
     * 合并给定的数组
     *
     * @param array    T[]
     * @param elements T[]
     * @param <T>      T
     * @return T[]
     */
    @SafeVarargs
    public static <T> T[] merge(T[] array, T... elements) {
        if (array != null && isNotEmpty(elements)) {
            final T[] result = newArray(array, elements);
            final int start = mergeAndGetLength(array, result, 0);
            mergeAndGetLength(elements, result, start);
            return result;
        }

        return array;
    }

    /**
     * 合并给定的数组
     *
     * @param array  T[]
     * @param arrays T[][]
     * @param <T>    T
     * @return T[]
     */
    @SafeVarargs
    public static <T> T[] merge(T[] array, T[]... arrays) {
        if (isNotEmpty(arrays)) {
            final T[] result = newArray(array, arrays);
            int start = 0;
            if (array != null) {
                start = mergeAndGetLength(array, result, 0);
            }
            for (T[] arr : arrays) {
                if (arr != null) {
                    start += mergeAndGetLength(arr, result, start);
                }
            }

            return result;
        }

        return array;
    }

    /**
     * 合并并获取新的长度
     *
     * @param src   T[]
     * @param dest  T[]
     * @param start offset
     * @param <T>   T
     * @return int
     */
    public static <T> int mergeAndGetLength(T[] src, T[] dest, int start) {
        System.arraycopy(src, 0, dest, start, src.length);
        return src.length;
    }

    /**
     * 创建新的数组
     *
     * @param array    T[]
     * @param elements T[][]
     * @param <T>      T
     * @return T[]
     */
    @SafeVarargs
    @SuppressWarnings("unchecked")
    public static <T> T[] newArray(T[] array, T[]... elements) {
        return (T[]) Array.newInstance(getArrayType(array, elements), getTotalLength(array, elements));
    }

    /**
     * 创建新的数组
     *
     * @param elements T
     * @param <T>      T
     * @return T[]
     */
    @SafeVarargs
    public static <T> T[] newArray(T... elements) {
        return elements;
    }

    /**
     * 获取数组长度
     *
     * @param array  T[]
     * @param arrays T[][]
     * @param <T>    T
     * @return int
     */
    @SafeVarargs
    public static <T> int getTotalLength(T[] array, T[]... arrays) {
        final int length = (array == null) ? 0 : array.length;
        return length + Arrays.stream(arrays).filter(Objects::nonNull).mapToInt(t -> t.length).sum();
    }

    /**
     * 获取数组类型
     *
     * @param array  T[]
     * @param arrays T[][]
     * @param <T>    T
     * @return Class
     */
    @SafeVarargs
    public static <T> Class<?> getArrayType(T[] array, T[]... arrays) {
        Class<?> result = getArrayType(array);
        if (result == null && arrays != null) {
            for (T[] arr : arrays) {
                if (arr != null) {
                    result = getArrayType(arrays[0]);
                    break;
                }
            }
        }

        Assert.notNull(result, "cannot found array type");
        return result;
    }

    /**
     * 获取数组类型
     *
     * @param array T[]
     * @param <T>   T
     * @return Class
     */
    public static <T> Class<?> getArrayType(T[] array) {
        return (array != null) ? array.getClass().getComponentType() : null;
    }
}
